package com.kamistoat.ruoyi.ruoyigateway.handler;

import com.kamistoat.ruoyi.ruoyicommoncore.exception.CaptchaException;
import com.kamistoat.ruoyi.ruoyicommoncore.web.domain.AjaxResult;
import com.kamistoat.ruoyi.ruoyigateway.service.ValidateCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.util.ArrayList;

/**
 * 验证码获取Handler.
 * <p>
 * 用响应式编程对service层进行抽取，注意覆写的handle方法的输入参数 ServerRequest 将直接映射调用此类时传入的响应式Request。
 * <p>
 * 需要注意的是service仍然是普通的service层，接口返回值仍然是ServletRequest。
 * 在商城项目中没有使用过响应式编程，所以写完Service层后直接就是Controller业务接口层了。
 * 而这里的Handler也可以理解成是Controller层，只不过返回的都是ServerResponse，而且返回的ServerResponse并不是直接返回给客户端，还需要经过 Router来进行处理。
 * <p>
 * HandlerFunction 是响应式编程第二构型中提供的函数式模型。接收ServerRequest，返回 Mono<ServerResponse>.
 * 这两个Server参数用来提供对底层HTTP消息(前端请求参数 和 后端service层返回结果) 的友好访问。
 * <p>
 * 实际上完全没有必要去继承 HandlerFunction，只要自己写的方法的输入和输出保证都是 ServerRequest 和 ServerResponse，那么就可以使用 Router进行绑定。
 * 例如下面的方法handle1()和handle2()，他们完全和HandlerFunction没有关系了，但是依然可以绑定到 Router中。
 * 理解这一点后，可以在任何模块中使用响应式编程，而不仅仅是在Gateway模块中。
 */
@Component
public class ValidateCodeHandler implements HandlerFunction<ServerResponse> {

    @Autowired
    ValidateCodeService validateCodeService;

    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest) {
        AjaxResult ajaxResult = new AjaxResult();

        try {
            //创建验证码
            ajaxResult = validateCodeService.createCaptcha();
        } catch (CaptchaException | IOException e) {
            return Mono.error(e);
        }

        /**
         * ServerResponse提供对 HTTP响应的访问，由于是不可变的，所以需要使用构造器构造。
         */
        return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajaxResult));
    }

    /**
     * 一个完全和 HandlerFunction接口没有关系的方法，可以理解成响应式编程中一个普通的 @Controller。
     * 只要输入和输出和 Handle保持相同，那么它就可以使用Router进行绑定
     */
    public Mono<ServerResponse> handle_1(ServerRequest serverRequest) {
        System.out.println("路径 /handle_1 的响应式handle被执行");
        return ServerResponse.ok().body("success", String.class);
    }

    /**
     * 由于输入无法像阻塞式编程那样携带路径参数，因此只能从ServerRequest中进行提取
     */
    public Mono<ServerResponse> handle_2(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        System.out.println("路径 /handle_2/{id} 的响应式handle被执行，获取路径参数:" + id);
        return ServerResponse.ok().body("success", String.class);
    }

    /**
     * 由于输入无法像阻塞式编程那样携带JSON数据，因此只能从ServerRequest中进行提取
     */
    public Mono<ServerResponse> handle_3(ServerRequest serverRequest) {
        // 加入请求中携带了 ArrayList类型的数据，可以用下面这种方法提取出来
        Mono<ArrayList> body = serverRequest.bodyToMono(ArrayList.class);
        System.out.println("路径 /handle_3 的响应式handle被执行，获取携带的body:" + body);
        return ServerResponse.ok().body("success", String.class);
    }

}

















